#include "common/pch.h"

#include <cftf/boot/app.h>

#include <boost/endian/conversion.hpp>

#include "listener/ggsession.h"
#include "cs/cs_message.h"
#include "cs/msg_descriptor.h"

const static size_t CRYPTED_SEND_LEN = 4;
const static size_t CRYPTED_RECV_LEN = 6;

GGSession::GGSession(cftf::net::TcpListener* listener, int socket_handle, boost::asio::ip::tcp::socket socket, std::size_t max_packet_len)
	: cftf::net::TcpSession(listener, socket_handle, std::move(socket), max_packet_len)
{
    seed_ = 2290717077;
}

void GGSession::SetKey(const unsigned char* data, std::size_t len)
{
    send_i_ = 0;
    send_j_ = 0;
    recv_i_ = 0;
    recv_j_ = 0;
    initialized_ = true;
    key_.clear();
    for (std::size_t i = 0; i < len; ++i) {
        key_.push_back(data[i]);
    }
}

bool GGSession::DecodePacket(boost::beast::flat_buffer& buff, bool& stop)
{
    while (buff.size() >= sizeof(ClientPktHeader)) {  
        ClientPktHeader header = *((ClientPktHeader*)buff.cdata().data());
        DecryptRecv((unsigned char*)&header, sizeof(header));
        header.size = boost::endian::big_to_native((unsigned short)(header.size));
        if (buff.size() < header.size + 2) {
            break;
        }
        *(ClientPktHeader*)buff.cdata().data() = header;
        cftf::boot::App::Instance().AddSocketMsg(GetSocketFrom(),
            cftf::kSeRead,
            GetSocketHandle(),
            (const char*)buff.cdata().data(),
            header.size + 2);
        buff.consume(header.size + 2);
    }
	return false;
}

void GGSession::DecryptRecv(unsigned char* data, size_t len)
{
    if (!initialized_) {
        return;
    }
    if (len < CRYPTED_RECV_LEN) {
        return;
    }
    for (size_t t = 0; t < CRYPTED_RECV_LEN; t++) {
        recv_i_ %= key_.size();
        unsigned char x = (data[t] - recv_j_) ^ key_[recv_i_];
        ++recv_i_;
        recv_j_ = data[t];
        data[t] = x;
    }
}

void GGSession::EncryptSend(unsigned char* data, size_t len)
{
    if (!initialized_) {
        return;
    }

    if (len < CRYPTED_SEND_LEN) {
        return;
    }

    for (size_t t = 0; t < CRYPTED_SEND_LEN; t++) {
        send_i_ %= key_.size();
        unsigned char x = (data[t] ^ key_[send_i_]) + send_j_;
        ++send_i_;
        data[t] = send_j_ = x;
    }
}
